#!/usr/bin/env python3
"""
Generate加密AlgorithmTestDataHeader file
SupportAES、SM4、SM2、RSA、ECC、Dilithium
每种Algorithm只保留一种最适合侧信道Analyze的操作
"""

import os
import argparse
from typing import Optional

# AlgorithmConfiguration（每种Algorithm只保留一种操作）
ALGORITHM_CONFIGS = {
    'aes': {
        'key_size': 16, 
        'block_size': 16,
        'type': 'symmetric',
        'operation': 'encrypt',  # Encryption operation（S-box泄露）
        'description': 'AES-128加密'
    },
    'sm4': {
        'key_size': 16, 
        'block_size': 16,
        'type': 'symmetric',
        'operation': 'encrypt',  # Encryption operation（S-box泄露）
        'description': 'SM4加密'
    },
    'sm2': {
        'key_size': 32, 
        'block_size': 32,
        'type': 'asymmetric',
        'operation': 'sign',  # Signing operation（私钥Scalar乘泄露）
        'description': 'SM2Digital Signature'
    },
    'rsa': {
        'key_size': 256, 
        'block_size': 128,
        'type': 'asymmetric',
        'operation': 'decrypt',  # Decryption operation（模幂运算泄露）
        'description': 'RSA私钥解密'
    },
    'ecc': {
        'key_size': 32, 
        'block_size': 32,
        'type': 'asymmetric',
        'operation': 'sign',  # Signing operation（Scalar乘泄露）
        'description': 'ECCDigital Signature(P-256)'
    },
    'dilithium': {
        'key_size': 32, 
        'block_size': 32,
        'type': 'asymmetric',
        'operation': 'sign',  # Signing operation（NTT变换泄露）
        'description': 'DilithiumDigital Signature'
    }
}

def generate_header(algorithm: str, num_traces: int, key: bytes, 
                   trace_delay_us: int = 1000,
                   output_file: Optional[str] = None):
    """
    GenerateTestDataHeader file
    
    Args:
        algorithm: Algorithm名称 (aes, sm4, sm2, rsa, ecc, dilithium)
        num_traces: Trace数量
        key: Key字节
        trace_delay_us: TRACE_START前的延时(微秒)
        output_file: Output file名
    """
    config = ALGORITHM_CONFIGS[algorithm]
    key_size = config['key_size']
    block_size = config['block_size']
    algo_type = config['type']
    operation = config['operation']  # UseAlgorithm固定的操作
    description = config['description']
    
    # Generate随机TestData
    test_data = [os.urandom(block_size) for _ in range(num_traces)]
    
    # 操作码Mapping
    operation_codes = {
        'encrypt': 0,
        'decrypt': 1,
        'sign': 2,
        'verify': 3,
        'ecdh': 4
    }
    op_code = operation_codes.get(operation, 0)
    
    # DefaultOutput file
    if output_file is None:
        output_file = f"{algorithm}_test_data.h"
    
    # GenerateHeader file
    with open(output_file, 'w') as f:
        f.write("/**\n")
        f.write(f" * {algorithm.upper()} TestData - 自动Generate\n")
        f.write(f" * Algorithm: {description}\n")
        f.write(f" * Trace数量: {num_traces}\n")
        f.write(f" * 操作Class型: {operation} (固定)\n")
        f.write(f" * 侧信道目标: {algo_type}Algorithm的{operation}操作\n")
        f.write(" */\n\n")
        f.write(f"#ifndef {algorithm.upper()}_TEST_DATA_H\n")
        f.write(f"#define {algorithm.upper()}_TEST_DATA_H\n\n")
        f.write("#include <stdint.h>\n\n")
        
        # ConfigurationParameters
        f.write(f"#define NUM_TRACES {num_traces}\n")
        f.write(f"#define {algorithm.upper()}_OPERATION {op_code}  // {operation}\n")
        f.write(f"#define TRACE_DELAY_US {trace_delay_us}\n")
        f.write(f"#define KEY_SIZE {key_size}\n")
        f.write(f"#define BLOCK_SIZE {block_size}\n\n")
        
        # Key
        f.write(f"// {algorithm.upper()} Key ({key_size}字节)\n")
        f.write(f"static const uint8_t {algorithm}_key[KEY_SIZE] = {{\n")
        
        # 每行8个字节
        for i in range(0, key_size, 8):
            chunk = key[i:i+8]
            f.write("    " + ", ".join(f"0x{b:02x}" for b in chunk))
            if i + 8 < key_size:
                f.write(",\n")
            else:
                f.write("\n")
        f.write("};\n\n")
        
        # TestData
        f.write("// TestData (PlaintextOrData)\n")
        f.write(f"static const uint8_t test_data[NUM_TRACES][BLOCK_SIZE] = {{\n")
        
        for i, data in enumerate(test_data):
            f.write("    {")
            # 每行8个字节
            for j in range(0, block_size, 8):
                if j > 0:
                    f.write("     ")
                chunk = data[j:j+8]
                f.write(", ".join(f"0x{b:02x}" for b in chunk))
                if j + 8 < block_size:
                    f.write(",\n")
            f.write("}")
            
            if i < len(test_data) - 1:
                f.write(",\n")
            else:
                f.write("\n")
        
        f.write("};\n\n")
        f.write(f"#endif // {algorithm.upper()}_TEST_DATA_H\n")
    
    print(f"[OK] GenerateTestDataHeader file: {output_file}")
    print(f"  Algorithm: {description}")
    print(f"  操作Class型: {operation} (固定)")
    print(f"  Trace数量: {num_traces}")
    print(f"  Key大小: {key_size} 字节")
    print(f"  块大小: {block_size} 字节")
    print(f"  Key: {key.hex()}")
    print(f"  侧信道Analyze目标: {algo_type}Algorithm的{operation}操作")
    
    return test_data

def main():
    parser = argparse.ArgumentParser(
        description='Generate加密AlgorithmTestDataHeader file',
        epilog='''
每种Algorithm的固定操作:
  AES:        encrypt  (S-boxOutput泄露)
  SM4:        encrypt  (S-boxOutput泄露)
  SM2:        sign     (Scalar乘泄露)
  RSA:        decrypt  (模幂运算泄露)
  ECC:        sign     (Scalar乘泄露)
  Dilithium:  sign     (NTT变换泄露)
        ''',
        formatter_class=argparse.RawDescriptionHelpFormatter
    )
    
    parser.add_argument('--algorithm', '-a', type=str, required=True,
                       choices=['aes', 'sm4', 'sm2', 'rsa', 'ecc', 'dilithium'],
                       help='AlgorithmClass型')
    
    parser.add_argument('--traces', '-n', type=int, default=100,
                       help='Trace数量 (Default: 100)')
    
    parser.add_argument('--key', type=str, default=None,
                       help='Key(hex)，Not指定则随机Generate')
    
    parser.add_argument('--output', '-o', type=str, default=None,
                       help='Output file名 (Default: {algorithm}_test_data.h)')
    
    parser.add_argument('--delay', type=int, default=100000,
                       help='TRACE_START前的延时(微秒) (Default: 100000, i.e.100ms)')
    
    args = parser.parse_args()
    
    algorithm = args.algorithm.lower()
    
    # GenerateOrParseKey
    key_size = ALGORITHM_CONFIGS[algorithm]['key_size']
    
    if args.key:
        key = bytes.fromhex(args.key)
        if len(key) != key_size:
            print(f"Error: Key必须Yes{key_size}字节({key_size*2}个十六进制字符)")
            return 1
    else:
        key = os.urandom(key_size)
    
    # GenerateHeader file
    generate_header(
        algorithm=algorithm,
        num_traces=args.traces,
        key=key,
        trace_delay_us=args.delay,
        output_file=args.output
    )
    
    return 0

if __name__ == '__main__':
    exit(main())
